<template>
	<view class="e-code-input">
		<view class="e-code-input__item" :style="[getItemStyle(index)]" v-for="(item, index) in codeLength"
			:key="index">
			<view class="e-code-input__item__dot" v-if="dot && codeArray.length > index"></view>
			<text v-else :style="itemTextStyle">{{codeArray[index]}}</text>
			<view class="e-code-input__item__line" v-if="mode === 'line'" :style="[lineStyle]"></view>
			<!-- #ifndef APP-PLUS -->
			<view v-if="isFocus && codeArray.length === index" :style="{backgroundColor: props.color}"
				class="e-code-input__item__cursor"></view>
			<!-- #endif -->
		</view>
		<input :disabled="props.disabledKeyboard" type="number" :focus="props.focus" :value="props.modelValue"
			:maxlength="props.maxlength" :adjustPosition="props.adjustPosition" class="e-code-input__input"
			@input="inputHandler" :style="{
				height: addUnit(props.size) 
			}" @focus="isFocus = true" @blur="isFocus = false" />
	</view>
</template>
<script lang="ts">
	import {
		defineComponent
	} from 'vue'
	import mpMixin from "../../libs/mixin/mpMixin";
	/**
	 * CodeInput 验证码输入
	 * @description 该组件一般用于验证用户短信验证码的场景，也可以结合uView的键盘组件使用
	 * @tutorial https://www.uviewui.com/components/codeInput.html
	 * @property {Boolean}			adjustPosition		键盘弹起时，是否自动上推页面（默认 true ）
	 * @property {String | Number}	maxlength			最大输入长度 （默认 6 ）
	 * @property {Boolean}			dot					是否用圆点填充 （默认 false ）
	 * @property {String}			mode				显示模式，box-盒子模式，line-底部横线模式 （默认 'box' ）
	 * @property {Boolean}			hairline			是否细边框 （默认 false ）
	 * @property {String | Number}	space				字符间的距离 （默认 10 ）
	 * @property {String | Number}	modelValue				预置值
	 * @property {Boolean}			focus				是否自动获取焦点 （默认 false ）
	 * @property {Boolean}			bold				字体和输入横线是否加粗 （默认 false ）
	 * @property {String}			color				字体颜色 （默认 '#606266' ）
	 * @property {String | Number}	fontSize			字体大小，单位px （默认 18 ）
	 * @property {String | Number}	size				输入框的大小，宽等于高 （默认 35 ）
	 * @property {Boolean}			disabledKeyboard	是否隐藏原生键盘，如果想用自定义键盘的话，需设置此参数为true （默认 false ）
	 * @property {String}			borderColor			边框和线条颜色 （默认 '#c9cacc' ）
	 * @property {String}			boxColor			背景颜色，仅mode为box时生效
	 * @property {Boolean}			disabledDot			是否禁止输入"."符号 （默认 true ）
	 *
	 * @event {Function}	change	输入内容发生改变时触发，具体见上方说明			value：当前输入的值
	 * @event {Function}	finish	输入字符个数达maxlength值时触发，见上方说明	value：当前输入的值
	 * @example	<e-code-input v-model="value4" :focus="true"></e-code-input>
	 */
	export default defineComponent({
		name: "e-code-input",
		mixins: [mpMixin],
	});
</script>
<script lang="ts" setup>
	import {
		ref,
		watch,
		computed,
		nextTick,
		toRefs
	} from 'vue'
	import {
		addUnit,
		getPx
	} from '../../libs/utils/_utils'
	import {
		codeInputProps,
		codeInputEmits
	} from './props';
	import type {
		StyleProperties
	} from "../../libs/tokens";
	import {
		useDefaultProps
	} from '../../libs/hooks'
	import componentsProps, {
		type DefaultProps
	} from "../../libs/config/componentsProps";

	const {
		codeInput: codeInputDefaultProps
	} = toRefs(componentsProps);

	const _props = defineProps(codeInputProps)
	const props = useDefaultProps < DefaultProps['codeInput'] > (_props, codeInputDefaultProps);
	const emit = defineEmits(codeInputEmits)

	const inputValue = ref('')
	const isFocus = ref(props.value.focus)
	
	// 根据长度，循环输入框的个数，因为头条小程序数值不能用于v-for
	const codeLength = computed(() => new Array(Number(props.value.maxlength)))
	// 将输入的值，转为数组，给item历遍时，根据当前的索引显示数组的元素
	const codeArray = computed(() => String(inputValue.value).split(''))

	watch(() => props.value.modelValue, (val: any) => {
		// 转为字符串，超出部分截掉
		inputValue.value = String(val||'').substring(0, Number(props.value.maxlength))
	}, {
		immediate: true
	})

	

	const itemTextStyle = computed(() => ({
		fontSize: addUnit(props.value.fontSize as string),
		fontWeight: props.value.bold ? 'bold' : 'normal',
		color: props.value.color
	}))

	// 下划线模式下，横线的样式
	const lineStyle = computed(() => {
		const style: StyleProperties = {}
		style.height = props.value.hairline ? '2px' : '4px'
		style.width = addUnit(props.value.size as string)
		// 线条模式下，背景色即为边框颜色
		style.backgroundColor = props.value.borderColor
		return style
	})
	// 循环item的样式
	const getItemStyle = (index: number) => {
		const style: StyleProperties = {
			width: addUnit(props.value.size as string),
			height: addUnit(props.value.size as string)
		}
		// 盒子模式下，需要额外进行处理
		if (props.value.mode === 'box') {
			// 设置盒子的边框，如果是细边框，则设置为0.5px宽度
			style.border = `${props.value.hairline ? 0.5 : 1}px solid ${props.value.borderColor as string}`
			style.backgroundColor = props.value.bgColor
			// 如果盒子间距为0的话
			if (getPx(props.value.space as string) === 0) {
				// 给第一和最后一个盒子设置圆角
				if (index === 0) {
					style.borderTopLeftRadius = '3px'
					style.borderBottomLeftRadius = '3px'
				}
				if (index === codeLength.value.length - 1) {
					style.borderTopRightRadius = '3px'
					style.borderBottomRightRadius = '3px'
				}
				// 最后一个盒子的右边框需要保留
				if (index !== codeLength.value.length - 1) {
					style.borderRight = 'none'
				}
			}
		}
		if (index !== codeLength.value.length - 1) {
			// 设置验证码字符之间的距离，通过margin-right设置，最后一个字符，无需右边框
			style.marginRight = addUnit(props.value.space as string)
		} else {
			// 最后一个盒子的有边框需要保留
			style.marginRight = 0
		}

		return style
	}
	// 监听输入框的值发生变化
	const inputHandler = async (e: {
		detail: {
			value: string;
		};
	}) => {
		const value = e.detail.value
		inputValue.value = value
		// 是否允许输入“.”符号
		if (props.value.disabledDot) {
			// 必须使用异步阻塞，防止emit事件触发后，用户修改了modelValue，导致inputValue的值不正确
			await nextTick()
			inputValue.value = value.replace('.', '')
		}
		// 未达到maxlength之前，发送change事件，达到后发送finish事件
		emit('change', value)
		// 修改通过v-model双向绑定的值
		emit('update:modelValue', value)
		// 达到用户指定输入长度时，发出完成事件
		if (String(value).length >= Number(props.value.maxlength)) {
			emit('finish', value)
		}
	}
</script>

<style lang="scss" scoped>
	@import "../../libs/theme/code-input.scss";
</style>
